#include "YGString.h"

namespace YoghurtGum
{

	void StringCopy(String& a_Dst, String& a_Src, int a_Start = -1, int a_Length = -1)
	{
		int width_dst = a_Dst.GetWidth();
		int width_src = a_Src.GetWidth();

		if (width_dst == 1)
		{
			char* dst = (char*)a_Dst.GetBytes();

			int len = (a_Length > -1) ? a_Length : a_Src.GetLength();
			if (len > a_Dst.GetLength()) { len = a_Dst.GetLength() - len; }

			if (width_dst == width_src)
			{
				char* src = (char*)a_Src.GetBytes();
				if (a_Start > 0) { src += a_Start; }

				for (int i = 0; i < len; i++) { *dst++ = *src++; }
				*dst = 0;
			}
			else
			{
				wchar_t* src = (wchar_t*)a_Src.GetBytes();
				if (a_Start > 0) { src += a_Start; }

				for (int i = 0; i < len; i++) { *dst++ = *(char*)src++; }
				*dst = 0;
			}
		}
		else if (width_dst == 2)
		{

		}
	}

	bool StringCompare(const String& a_Left, const String& a_Right, int a_Start = -1, int a_Length = -1)
	{
		int len_l = a_Left.GetLength();
		int len_r = a_Right.GetLength();
		//if (a_Length == -1 && len_l != len_r) { return false; }

		int len;
		if (a_Length > -1)
		{
			len = a_Length;
		}
		else
		{
			len = (len_l > len_r) ? len_l : len_r;
		}

		int width_l = a_Left.GetWidth();
		int width_r = a_Right.GetWidth();

		if (width_l == 1)
		{
			if (width_l == width_r)
			{
				const char* cmp_l = a_Left.GetBytes();
				const char* cmp_r = a_Right.GetBytes();

				if (a_Start > -1) { cmp_l += a_Start; }

				for (int i = 0; i < len; i++)
				{
					if (i > len_l || i > len_r) { return false; }
					if (*cmp_l++ != *cmp_r++) { return false; }
				}

				return true;
			}
			else
			{
				const char* cmp_l    = a_Left.GetBytes();
				const wchar_t* cmp_r = (wchar_t*)a_Right.GetBytes();

				if (a_Start > -1) { cmp_l += a_Start; }

				for (int i = 0; i < len; i++)
				{
					if (i > len_l || i > len_r) { return false; }
					if (*cmp_l++ != *cmp_r++) { return false; }
				}

				return true;
			}
		}
		else
		{
			if (width_l == width_r)
			{
				const wchar_t* cmp_l = (wchar_t*)a_Left.GetBytes();
				const wchar_t* cmp_r = (wchar_t*)a_Right.GetBytes();

				if (a_Start > -1) { cmp_l += a_Start; }

				for (int i = 0; i < len; i++)
				{
					if (i > len_l || i > len_r) { return false; }
					if (*cmp_l++ != *cmp_r++) { return false; }
				}

				return true;
			}
			else
			{
				const wchar_t* cmp_l = (wchar_t*)a_Left.GetBytes();
				const char* cmp_r    = a_Right.GetBytes();

				if (a_Start > -1) { cmp_l += a_Start; }

				for (int i = 0; i < len; i++)
				{
					if (i > len_l || i > len_r) { return false; }
					if (*cmp_l++ != *cmp_r++) { return false; }
				}

				return true;
			}
		}

		return false;
	}

	// ================================
	// Constructor
	// ================================

	struct String::ArgList
	{
		int* start;
		int* skip;
		int* offset;
		int total;
		int current;
		char* temp;
		int prev_pos;
	};

	String::String()
	{
		m_ArgList = NULL;

		m_Length = 0;
		m_Maximum = -1;
		m_Data = NULL;
		Clear();

		_Append = &String::_AppendDyn;
		_Prepend = &String::_PrependDyn;
	}

	String::String(int a_Maximum)
	{
		m_ArgList = NULL;

		m_Length = a_Maximum;
		m_Maximum = a_Maximum;
		m_Data = new char[m_Maximum + 1];
		Clear();

		_Append = &String::_AppendFix;
		_Prepend = &String::_PrependFix;
	}

	String::String(const char* a_String)
	{
		m_ArgList = NULL;

		m_Length = (int)strlen(a_String);
		m_Maximum = m_Length;
		m_Width = 1;

		m_Data = new char[m_Length + 1];
		memcpy(m_Data, a_String, m_Length * m_Width);
		m_Data[m_Length * m_Width] = 0;

		_Append = &String::_AppendDyn;
		_Prepend = &String::_PrependDyn;
	}

	String::String(const char* a_String, int a_Maximum)
	{
		m_ArgList = NULL;

		m_Length = (int)strlen(a_String);
		m_Maximum = a_Maximum;
		m_Width = 1;

		m_Data = new char[m_Maximum * m_Width + 1];
		memcpy(m_Data, a_String, m_Length * m_Width);
		m_Data[m_Length * m_Width + 1] = 0;

		_Append = &String::_AppendFix;
		_Prepend = &String::_PrependFix;
	}

#ifdef YG_STRING_WIDE_SUPPORT

	String::String(const wchar_t* a_String)
	{
		m_ArgList = NULL;

		m_Length = (int)wcslen(a_String);
		m_Maximum = m_Length;
		m_Width = 2;

		m_Data = new char[(m_Length + 1) * m_Width];
		memcpy(m_Data, a_String, m_Length * m_Width);
		m_Data[m_Length * m_Width + 0] = 0;
		m_Data[m_Length * m_Width + 1] = 0;

		_Append = &String::_AppendDyn;
		_Prepend = &String::_PrependDyn;
	}

	String::String(const wchar_t* a_String, int a_Maximum)
	{
		m_ArgList = NULL;

		m_Length = (int)wcslen(a_String);
		m_Maximum = a_Maximum;
		m_Width = 2;

		m_Data = new char[m_Maximum * m_Width];
		memcpy(m_Data, a_String, m_Length * m_Width);
		m_Data[m_Length * m_Width + 0] = 0;
		m_Data[m_Length * m_Width + 1] = 0;

		_Append = &String::_AppendFix;
		_Prepend = &String::_PrependFix;
	}

#endif

	String::String(const String& a_String)
	{
		m_ArgList = NULL;

		m_Length = -1;
		m_Maximum = -1;
		m_Width = -1;

		_Append = &String::_AppendDyn;
		_Prepend = &String::_PrependDyn;
		(this->*_Append)(a_String);
	}

	String::String(const String& a_String, int a_Maximum)
	{
		m_ArgList = NULL;

		m_Length = a_String.GetLength();
		m_Maximum = a_Maximum;
		m_Width = -1;

		_Append = &String::_AppendFix;
		_Prepend = &String::_PrependFix;
		(this->*_Append)(a_String);
	}

	String::~String()
	{

	}

	// ================================
	// Operators
	// ================================

	String::operator char* ()
	{
		if (m_Width == 1)
		{
			return m_Data;
		}
		else
		{
			char* result = new char[m_Length + 1];
			char* dst = result;
			wchar_t* src = (wchar_t*)m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (char)(*src++ & 0xFF);
			}
			*dst++ = 0;
			return result;
		}

		return NULL;
	}

	String::operator wchar_t* ()
	{
		if (m_Width == 2)
		{
			return (wchar_t*)m_Data;
		}
		else
		{
			wchar_t* result = new wchar_t[m_Length + 1];
			wchar_t* dst = result;
			char* src = m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (wchar_t)(*src++);
			}
			*dst++ = 0;
			return result;
		}

		return NULL;
	}

	bool String::operator ! ()
	{
		return (GetLength() < 1);
	}

	String& String::operator = (const char* a_String)
	{
		Clear();
		Append(a_String);

		return *this;
	}

	String& String::operator = (String a_String)
	{
		Clear();
		Append(a_String.GetBytes());

		return *this;
	}

	String String::operator + (const char* a_String)
	{
		String result(m_Data);
		result.Append(a_String);
		return result;
	}

	String String::operator + (String& a_String)
	{
		String result(m_Data);
		result.Append(a_String.GetBytes());
		return result;
	}

	String& String::operator += (const char* a_String)
	{
		(this->*_Append)(String(a_String));
		return *this;
	}

#ifdef YG_STRING_WIDE_SUPPORT

	String& String::operator += (const wchar_t* a_String)
	{
		(this->*_Append)(String(a_String));
		return *this;
	}

#endif

	String& String::operator += (String& a_String)
	{
		(this->*_Append)(a_String);
		return *this;
	}

	bool String::operator == (const char* a_String)
	{
		if (IsEmpty()) { return false; }

		return (StringCompare(*(String*)this, String(a_String)));
	}

#ifdef YG_STRING_WIDE_SUPPORT

	bool String::operator == (const wchar_t* a_String)
	{
		if (IsEmpty()) { return false; }

		return (StringCompare(*this, String(a_String)));
	}

#endif

	bool String::operator == (const String& a_String)
	{
		if (IsEmpty() || a_String.IsEmpty()) { return false; }

		return (!strncmp(m_Data, a_String.GetBytes(), (size_t)a_String.GetLength()));
	}

	bool String::operator != (const char* a_String)
	{
		if (IsEmpty() || a_String.IsEmpty()) { return false; }
	}

	// ================================
	// Iterators
	// ================================

	String::iterator String::Begin()
	{
		return &m_Data[0];
	}

	String::iterator String::End()
	{
		return &m_Data[m_Length - 1];
	}

	String::iterator String::operator [] (int a_Index)
	{
		if (a_Index < 0 || a_Index > m_Length - 1) { return NULL; }

		return &m_Data[a_Index];
	}

	char String::At( int a_Index )
	{
		if (a_Index < 0 || a_Index > m_Length - 1) { return 0; }

		return m_Data[a_Index];
	}

	// ================================
	// Functions
	// ================================

	bool String::IsEmpty()
	{
		return (!m_Data || m_Length == 0);
	}

	int String::FindRight( char a_Char )
	{
		char* result = strrchr(m_Data, (int)a_Char);
		if (result)
		{
			int found = (int)(result - m_Data);
			return found;
		}
		return -1;
	}

	int String::FindLeft( char a_Char )
	{
		char* result = strchr(m_Data, (int)a_Char);
		if (result)
		{
			int found = (int)(result - m_Data);
			return found;
		}
		return -1;
	}

	String String::Middle(int a_Begin, int a_Length)
	{
		int len = (a_Length == -1) ? m_Maximum : a_Length;

		if (len + a_Begin > m_Maximum) { len -= a_Begin; }

		char* temp = new char[len];
		temp[len] = 0;
		String result(temp);
		StringCopy(result, *this, a_Begin, len);

		return String(result.GetBytes());
	}

	String String::Left(int a_Length)
	{
		int len = (a_Length == -1) ? m_Maximum : a_Length;
		if (len < 0) { return String(); }

		char* temp = new char[len];
		temp[len] = 0;
		String result(temp);
		StringCopy(result, *this, 0, len);

		return String(result.GetBytes());
	}

	String String::Right(int a_Length)
	{
		int len = (a_Length == -1) ? m_Maximum : a_Length;
		if (len < 0) { return String(); }

		int offset = m_Maximum - len;
		if (offset < 0) { offset = 0; }

		char* temp = new char[len];
		temp[len] = 0;
		String result(temp);
		StringCopy(result, *this, offset, len);

		return String(result.GetBytes());
	}

	// TODO: LeftJustified wide string
	String String::LeftJustified(int a_Length, char a_Padding /*= ' '*/, bool a_Truncate /*= false*/)
	{
		int len;
		int copy;
		int justified = 0;

		if (a_Truncate)
		{
			len = a_Length;
			justified = (m_Maximum - len);
			copy = len;
			if (justified < 0) { justified = 0; }
		}
		else
		{
			if (a_Length < m_Maximum)
			{
				char* temp = new char[m_Length];
				//YG_STRCPY(temp, m_Length + 1, m_Data);
				strcpy(temp, m_Data);
				return String(temp);
			}
			else
			{
				len = a_Length + 1;
				justified = (len - m_Maximum);
			}
			copy = m_Maximum + 1;
		}
		if (len < 0) { return String(); }

		char* temp = new char[len];
		YG_STRNCPY(temp, copy + 1, m_Data, copy);

		if (!a_Truncate)
		{
			int i;
			for (i = m_Maximum; i < a_Length; ++i) { temp[i] = a_Padding; }
			temp[i] = 0;
		}

		return String(temp);
	}

	bool String::Clear()
	{
		if (m_Data)
		{
			m_Data[0] = 0;
			m_Length = 0;
		}

		return true;
	}

	String& String::Append(const char* a_String)
	{
		return (this->*_Append)(String(a_String));
	}

#ifdef YG_STRING_WIDE_SUPPORT

	String& String::Append(const wchar_t* a_String)
	{
		return (this->*_Append)(String(a_String));
	}

#endif

	String& String::Append(const String& a_String )
	{
		return (this->*_Append)(a_String);
	}

	String& String::Prepend(const char* a_String)
	{
		return (this->*_Prepend)(String(a_String));
	}

#ifdef YG_STRING_WIDE_SUPPORT

	String& String::Prepend( const wchar_t* a_String )
	{
		return (this->*_Prepend)(String(a_String));
	}

#endif

	String& String::Prepend(const String& a_String)
	{
		return (this->*_Prepend)(a_String);
	}

	bool String::Resize(int a_Maximum /* = -1*/)
	{
		if (a_Maximum == -1) { a_Maximum = m_Maximum * 2; }

		char* temp = new char[a_Maximum * m_Width];
		size_t length = (a_Maximum > m_Maximum) ? (size_t)a_Maximum : m_Length;
		memcpy(temp, m_Data, length * m_Width);
		delete m_Data;
		m_Data = temp;
		m_Data[m_Length * m_Width] = 0;
		m_Maximum = a_Maximum;

		return true;
	}

	int String::GetLength() const
	{
		return m_Length;
	}

	int String::GetWidth() const
	{
		return m_Width;
	}

	bool String::BeginsWith(String a_String)
	{
		if (!m_Data || m_Length == 0) { return false; }

		return (StringCompare(*this, a_String, 0, a_String.GetLength()));
	}

	bool String::EndsWith(String a_String)
	{
		if (!m_Data || m_Length == 0) { return false; }

		return (StringCompare(*this, a_String, m_Length - a_String.GetLength(), a_String.GetLength()));
	}

	// ================================
	// Converters
	// ================================

	short String::ToShort(bool* a_Check /*= 0*/)
	{
		int result = ToLong(a_Check);
		return (short)result;
	}

	long String::ToLong(bool* a_Check /*= 0*/)
	{
		int result;
		if (m_Width == 2)
		{
			char* temp = new char[m_Length + 1];
			char* dst = temp;
			wchar_t* src = (wchar_t*)m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (char)(*src++ & 0xFF);
			}
			*dst = 0;

			result = atol(temp);
			delete temp;
		}
		else
		{
			result = atol(m_Data);
		}

		if (a_Check) { *a_Check = true; }
		return result;
	}

	unsigned short String::ToUShort(bool* a_Check /*= 0*/)
	{
		unsigned int result = ToULong(a_Check);
		return (unsigned short)result;
	}

	unsigned long String::ToULong(bool* a_Check /*= 0*/)
	{
		int result;
		if (m_Width == 2)
		{
			char* temp = new char[m_Length + 1];
			char* dst = temp;
			wchar_t* src = (wchar_t*)m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (char)(*src++ & 0xFF);
			}
			*dst = 0;

			result = atol(temp);
			delete temp;
		}
		else
		{
			result = atol(m_Data);
		}

		if (a_Check) { *a_Check = true; }
		if (result < 0) { result *= -1; }
		return result;
	}

	float String::ToFloat(bool* a_Check /*= 0*/)
	{
		double result;

#ifdef YG_STRING_WIDE_SUPPORT

		if (m_Width == 2)
		{

/*#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

			result = _wtof((wchar_t*)m_Data);

#else*/

			char* temp = new char[m_Length + 1];
			char* dst = temp;
			wchar_t* src = (wchar_t*)m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (char)(*src++ & 0xFF);
			}
			*dst = 0;

			result = atof(temp);
			delete temp;

//#endif

		}
		else

#endif
		
		{
			result = atof(m_Data);
		}

		if (a_Check) { *a_Check = true; }
		return (float)result;
	}

	double String::ToDouble( bool* a_Check /*= 0*/ )
	{
		double result;

		if (m_Width == 2)
		{

/*#if (YG_OS_TYPE == YG_OS_TYPE_WINDOWSMOBILE)

			result = _wtof((wchar_t*)m_Data);
			
#else*/

			char* temp = new char[m_Length + 1];
			char* dst = temp;
			wchar_t* src = (wchar_t*)m_Data;
			for (int i = 0; i < m_Length; i++)
			{
				*dst++ = (char)(*src++ & 0xFF);
			}
			*dst = 0;

			result = atof(temp);
			delete temp;

//#endif

		}
		else
		{
			result = atof(m_Data);
		}

		if (a_Check) { *a_Check = true; }
		return result;
	}

	// ================================
	// Fixed vs Dynamic
	// ================================

	String& String::_AppendFix(const String& a_String )
	{
		if (m_Width == -1)
		{
			m_Width = a_String.GetWidth();
			//m_Maximum = a_String.GetLength();
			m_Data = new char[m_Maximum * m_Width + 1];
			m_Length = 0;
		}

		int len_dst = m_Length;
		int len_src = a_String.GetLength();
		size_t len = len_src;

		if (len_dst + len_src > m_Maximum)
		{
			len = (m_Maximum - len_dst);
			if (len == 0) { return *this; }
		}
		if ((int)len > m_Maximum) { len = m_Maximum; }

		char* dst = m_Data + (m_Width * m_Length);
		const char* src = a_String.GetBytes();
		int width_dst = m_Width;
		int width_src = a_String.GetWidth();

		if (width_dst == width_src)
		{
			memcpy(dst, src, len * width_src);
			dst[len * width_src] = 0;
			int i = 0;
		}
		if (width_dst > width_src)
		{
			for (size_t i = 0; i < len; i++)
			{
				*dst = *src;
				dst += width_dst;
				src += width_src;
			}
		}
		else if (width_dst < width_src)
		{
			wchar_t* src_w = (wchar_t*)src;

			for (int i = 0; i < len_src; i++)
			{
				*dst = (char)(*src_w & 0xFF);
				dst++;
				src_w++;
			}
		}
		m_Length += len;

		return *this;
	}

	String& String::_AppendDyn(const String& a_String )
	{
		if (m_Maximum == -1)
		{
			m_Maximum = a_String.GetLength() + 1;
			m_Width = a_String.GetWidth();
			m_Data = new char[m_Maximum];
			m_Data[0] = 0;
			m_Length = 0;
		}

		int len_src = a_String.GetLength();
		int checklen = m_Length + len_src + 1;
		if (checklen > m_Maximum)
		{
			while (checklen > m_Maximum) { m_Maximum *= 2; }
			Resize(m_Maximum);
		}

		char* dst = m_Data + (m_Width * m_Length);
		const char* src = a_String.GetBytes();
		int width_dst = m_Width;
		int width_src = a_String.GetWidth();

		if (width_dst == width_src)
		{
			memcpy(dst, src, len_src * width_src);
		}
		else if (width_dst > width_src)
		{
			for (int i = 0; i < len_src; i++)
			{
				*dst = *src;
				dst += width_dst;
				src += width_src;
			}
		}
		else if (width_dst < width_src)
		{
			wchar_t* src_w = (wchar_t*)src;

			for (int i = 0; i < len_src; i++)
			{
				*dst = (char)(*src_w & 0xFF);
				dst++;
				src_w++;
			}
		}
		m_Length += len_src;

		m_Data[m_Length * m_Width] = 0;
		if (m_Width > 1) { m_Data[m_Length * m_Width + 1] = 0;}

		return *this;
	}

	String& String::_PrependFix(const String& a_String)
	{
		int maximum = m_Maximum;
		int len_dst = m_Length;
		int len_src = a_String.GetLength();
		int total = len_dst + len_src;

		if (total > m_Maximum)
		{
			if (len_src > m_Length) { len_src = m_Maximum; }
			len_dst = m_Maximum - len_src;
		}

		char* temp = new char[maximum];
		YG_STRNCPY(temp, maximum + 1, a_String.GetBytes(), len_src);
		YG_STRNCAT(temp, maximum + 1, m_Data, len_dst);

		if (m_Data) { delete m_Data; }
		m_Data = new char[maximum];
		//YG_STRCPY(m_Data, maximum + 1, temp);
		strcpy(m_Data, temp);
		m_Length = (int)strlen(m_Data);

		return *this;
	}

	String& String::_PrependDyn(const String& a_String)
	{
		int maximum = m_Maximum;
		int total = m_Length + a_String.GetLength();

		if (total > m_Maximum)
		{
			while (total > maximum) { maximum *= 2; }
			m_Maximum = maximum;
		}

		char* temp = new char[maximum];
		YG_STRCPY(temp, maximum + 1, a_String.GetBytes());
		YG_STRNCAT(temp, maximum + 1, m_Data, total);

		if (m_Data) { delete m_Data; }
		m_Data = new char[maximum];
		YG_STRCPY(m_Data, maximum + 1, temp);
		m_Length = (int)strlen(m_Data);

		return *this;
	}

	void String::_ArgList()
	{
		if (!m_Data || m_ArgList) { return; }

		delete m_ArgList;
		m_ArgList = new ArgList;

		int start[32] = { -1 };
		int skip[32] = { -1 };

		int current = 0;
		int value = 0;
		int times = 0;
		int highest = 0;
		int numbers_found = 0;
		bool escape = true;
		char number_str[8] = { 0 };

		int w = m_Width;

		for (int i = 0; i < m_Length * w; )
		{
			char number;
			if (escape)
			{
				if (m_Data[i] != '%')
				{
					i += w;
					continue;
				}
				else
				{
					escape = false;
					i += w;
					number = m_Data[i];
				}
			}
			else
			{
				i += w;
				number = m_Data[i];
			}

			if (number < '0' || number > '9')
			{
				escape = true;

				if (numbers_found > 0)
				{
					value = atoi(number_str);

					highest = (value > highest) ? value : highest;

					value -= 1;
					start[value] = i - w;
					skip[value] = (int)strlen(number_str) * w;
					for (int j = 0; j < 8; j++) { number_str[j] = 0; }
				}

				value = 0;
				current = 0;
				numbers_found = 0;
				continue;
			}
			else
			{
				numbers_found++;
			}
			number_str[current++] = number;
		}

		m_ArgList->start = new int[highest];
		m_ArgList->skip = new int[highest];
		m_ArgList->offset = new int[highest];
		for (int i = 0; i < highest; i++)
		{
			m_ArgList->start[i]   = start[i];
			m_ArgList->skip[i]    = skip[i];
			m_ArgList->offset[i]  = 0;
		}
		m_ArgList->total = highest;
		m_ArgList->current = 0;
		m_ArgList->temp = NULL;
		m_ArgList->prev_pos = -1;
	}

	String& String::_ArgHelper(const char* a_Middle, int a_Length, int a_Width)
	{
		while (m_ArgList->start[m_ArgList->current] == -1)
		{
			m_ArgList->current++;
		}

		// offsets

		int len_left = m_ArgList->start[m_ArgList->current] + m_ArgList->offset[m_ArgList->current] - m_Width;
		int start_right = len_left + m_Width + m_ArgList->skip[m_ArgList->current];
		int len_right = (m_Length * m_Width) - start_right;

		// temporary data

		int len_total = len_left + (a_Length * m_Width) + len_right;
		m_ArgList->temp = new char[len_total];
		char* dst = m_ArgList->temp;

		// left

		memcpy(dst, m_Data, len_left);
		dst += len_left;

		// middle

		const char* src = a_Middle;
		if (m_Width == 2)
		{
			for (int i = 0; i < a_Length; i++)
			{
				*dst++ = *src++;
				*dst++ = *src++;
			}
		}
		else
		{
			for (int i = 0; i < a_Length; i++)
			{
				*dst++ = *src;
				src += a_Width;
			}
		}

		// right

		memcpy(dst, m_Data + start_right, len_right);

		// fixing offsets

		int start = m_ArgList->start[m_ArgList->current];
		int offset = a_Length - m_ArgList->skip[m_ArgList->current] - 1;
		for (int i = m_ArgList->current; i < m_ArgList->total; i++)
		{
			if (m_ArgList->start[i] > start) { m_ArgList->offset[i] += offset; }
		}

		m_ArgList->current++;

		// getting new length

		m_Maximum = len_total;
		m_Length = (len_left / m_Width) + a_Length + (len_right / m_Width);

		// copying data

		memcpy(m_Data, m_ArgList->temp, len_total);
		memset(m_Data + len_total, 0, m_Width);

		// cleaning up

		delete m_ArgList->temp;

		return *this;
	}


	String& String::Arg( short a_Number )
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA(a_Number, num, 256, 10);
			len_num = (int)strlen(num);
		}
		else
		{
			YG_ITOW(a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

		return _ArgHelper(num, len_num, 1);
	}

	String& String::Arg( unsigned short a_Number )
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA(a_Number, num, 256, 10);
			len_num = (int)strlen(num);
		}

#ifdef YG_STRING_WIDE_SUPPORT

		else
		{
			YG_ITOW(a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

#endif

		return _ArgHelper(num, len_num, 1);
	}

	String& String::Arg(long a_Number)
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA(a_Number, num, 256, 10);
			len_num = (int)YG_STRLEN(num);
		}

#ifdef YG_STRING_WIDE_SUPPORT

		else
		{
			YG_ITOW(a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

#endif

		return _ArgHelper(num, len_num, 1);
	}

	String& String::Arg(unsigned long a_Number)
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA((int)a_Number, num, 256, 10);
			len_num = (int)strlen(num);
		}

#ifdef YG_STRING_WIDE_SUPPORT

		else
		{
			YG_ITOW((int)a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

#endif

		return _ArgHelper(num, len_num, 1);
	}

	String& String::Arg(int a_Number)
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA((int)a_Number, num, 256, 10);
			//len_num = (int)strlen(num);
			len_num = (int)YG_STRLEN(num);
		}

#ifdef YG_STRING_WIDE_SUPPORT

		else
		{
			//_itow((int)a_Number, (wchar_t*)num, 10);
			YG_ITOW(a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

#endif

		return _ArgHelper(num, len_num);
	}

	String& String::Arg(unsigned int a_Number)
	{
		_ArgList();

		char num[256];
		int len_num = 0;
		if (m_Width == 1)
		{
			YG_ITOA((int)a_Number, num, 256, 10);
			len_num = (int)strlen(num);
		}

#ifdef YG_STRING_WIDE_SUPPORT

		else
		{
			//_itow((int)a_Number, (wchar_t*)num, 10);
			YG_ITOW(a_Number, (wchar_t*)num, 256, 10);
			len_num = (int)wcslen((wchar_t*)num);
			return _ArgHelper(num, len_num, 2);
		}

#endif

		return _ArgHelper(num, len_num, 1);
	}

	String& String::Arg(const char* a_String)
	{
		_ArgList();

		return _ArgHelper(a_String, (int)strlen(a_String));
	}

#ifdef YG_STRING_WIDE_SUPPORT

	String& String::Arg(const wchar_t* a_String)
	{
		_ArgList();

		return _ArgHelper((const char*)a_String, (int)wcslen(a_String), 2);
	}

#endif

	String& String::Arg( float a_Number, int a_Precision /*= -1*/ )
	{
		_ArgList();

		char num[256];
		if (a_Precision < 1)
		{
			YG_FTOA(a_Number, num, 256, 254);
		}
		else
		{

			YG_FTOA(a_Number, num, 256, 254);
		}
		int len_num = (int)YG_STRLEN(num);

		/*char format[8];
		if (a_Precision == -1) { YG_STRCPY(format, 9, "%f"); }
		else
		{
			YG_SPRINTF(format, 9, "%%.%df", a_Precision);
		}
		YG_SPRINTF(num, 257, format, a_Number);
		int len_num = (int)strlen(num);*/

		return _ArgHelper(num, len_num);
	}

	String& String::Arg( double a_Number, int a_Precision /*= -1*/ )
	{
		_ArgList();

		char num[256];
		char format[8];
		if (a_Precision == -1) { YG_STRCPY(format, 9, "%lf"); }
		else
		{
			YG_SPRINTF(format, 9, "%%.%dlf", a_Precision);
		}
		YG_SPRINTF(num, 257, format, a_Number);
		int len_num = (int)strlen(num);

		return _ArgHelper(num, len_num);
	}

};
